home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
176-200
/
disk_193
/
zc
/
fix.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-06
|
9KB
|
460 lines
/* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to redistribute it freely, with the
* following restrictions:
* 1) No charge may be made other than reasonable charges for reproduction.
* 2) Modified versions must be clearly marked as such.
* 3) The authors are not responsible for any harmful consequences
* of using this software, even if they result from defects in it.
*
* fix.c
*
* Motorola has is not consistent in what operations allow
* which operands. This section compensates for that --
* tries to find the best way to do something.
*/
#include <stdio.h>
#include "param.h"
#include "nodes.h"
#include "flags.h"
#include "bstok.h"
#include "gen.h"
#include "ops.h"
#define FAIL 0
#define OKAY 1
#define CL_IMM IOPD
#define CL_AREG AOPD
#define CL_DREG DOPD
#define CL_ADR MOPD
#define RETAREG 0x100
#define RETDREG 0x200
#define RETLEFT 0x400
#define RETRIGHT 0x800
#define LISTMP 1
#define RISTMP 2
#define NDASSOC 4
#define CANRL 8
#define CANLR 0x10
#define CANRD 0x20
#define CANDL 0x40
#define CANLD 0x80
#define CANDD 0x100
#define CANDR 0x200
struct mtbl {
int restr;
char *code;
int needregs;
} tbl2[] = {
{LISTMP|CANRL,
"\tN.S\t>A,<A\n", RETLEFT},
{RISTMP|CANLR|NDASSOC,
"\tN.S\t<A,>A\n", RETRIGHT},
{CANRD,
"\tmove.S\t<A,A\n\tN.S\t>A,A\n", RETDREG},
{CANLD|NDASSOC,
"\tmove.S\t>A,A\n\tN.S\t<A,A\n", RETDREG},
/* only EOR and shifts get to here */
{CANDL|LISTMP,
"\tmove.S\t>A,R1\n\tN.S\tR1,A\n", RETLEFT|1},
{CANDR|RISTMP|NDASSOC,
"\tmove.S\t<A,R1\n\tN.S\tR1,A\n", RETRIGHT|1},
{CANDD,
"\tmove.S\t<A,A\n\tmove.S\t>A,R1\n\tN.S\tR1,A\n",
RETDREG|1},
{0}
};
struct mtbl tblmul[] = {
{CANRL|LISTMP,
"\tmulU\t>A,<A\n", RETLEFT},
{CANLR|RISTMP,
"\tmulU\t<A,>A\n", RETRIGHT},
{CANRD,
"\tmove.w\t>A,A\n\tmulU\t<A,A\n", RETDREG},
{0}
};
struct mtbl tbldiv[] = {
{CANRL|LISTMP,
"\text.l\t<A\n\tdivs\t>A,<A\n", RETLEFT},
{CANRD,
"\tmove.w\t<A,A\n\text.l\tA\n\tdivs\t>A,A\n", RETDREG},
{0}
};
struct mtbl tbludiv[] = {
{CANRD,
"\tclr.l\tA\n\tmove.w\t<A,A\n\tdivu\t>A,A\n", RETDREG},
{0}
};
struct mtbl tblc[] = {
{CANRL,
"\tcmp.<S\t>A,<A\n", 0},
{CANRD,
"\tmove.<S\t<A,R1\n\tcmp.<S\t>A,R1\n", 1},
/* shouldnt get to here! */
{CANDL,
"\tmove.<S\t>A,R1\n\tcmp.<S\tR1,<A\n", 1},
{CANDD,
"\tmove.<S\t>A,R1\n\tmove.<S\t<A,R2\n\tcmp.<S\tR1,R2\n", 2},
{0}
};
struct mtbl tblas[] = {
{CANRL,
"\tN.S\t>A,<A\n", RETLEFT},
{CANDL,
"\tmove.S\t>A,R1\n\tN.S\tR1,A\n", 1|RETLEFT},
/* only MUL, DIV and shifts should get to here */
{CANRD,
"\tmove.S\t<A,A\n\tN.S\t>A,A\n\tmove.S\tA,<A\n",
RETDREG},
{CANLD|NDASSOC,
"\tmove.S\t>A,A\n\tN.S\t<A,A\n\tmove.S\tA,<A\n",
RETDREG},
{CANDD,
"\tmove.S\t<A,A\n\tmove.S\t>A,R1\n\tN.S\tR1,A\n\tmove.S\tA,<A\n",
RETDREG|1},
{0}
};
struct mtbl tblamul[] = {
{CANRL,
"\tmulU\t>A,<A\n", RETLEFT},
{CANLR|RISTMP,
"\tmulU\t<A,>A\n\tmove.w\t>A,<A\n", RETRIGHT},
{CANRD,
"\tmove.w\t<A,A\n\tmulU\t>A,A\n\tmove.w\tA,<A\n", RETDREG},
{0}
};
struct mtbl tbladiv[] = {
{CANRL,
"\text.l\t<A\n\tdivs\t>A,<A\n", RETLEFT},
{CANRD,
"\tmove.w\t<A,A\n\text.l\tA\n\tdivs\t>A,A\n\tmove.w\tA,<A\n",
RETDREG},
{0}
};
struct mtbl tbluadiv[] = {
{CANRD,
"\tclr.l\tA\n\tmove.w\t<A,A\n\tdivu\t>A,A\n\tmove.w\tA,<A\n",
RETDREG},
{0}
};
struct mtbl tblamod[] = {
{CANRL,
"\text.l\t<A\n\tdivs\t>A,<A\n\tswap\t<A\n", RETLEFT},
{CANRD,
"\tmove.w\t<A,A\n\text.l\tA\n\tdivs\t>A,A\n\tswap\tA\n\tmove.w\tA,<A\n",
RETDREG},
{0}
};
struct mtbl tbluamod[] = {
{CANRD,
"\tclr.l\tA\n\tmove.w\t<A,A\n\tdivu\t>A,A\n\tswap\tA\n\tmove.w\tA,<A\n",
RETDREG},
{0}
};
class(np)
NODEP np;
{
switch (np->g_token) {
case ICON:
return CL_IMM;
case ONAME:
return (np->g_flags & IMMEDID) ? CL_IMM : CL_ADR;
case OREG:
return (np->g_flags & IMMEDID) ? CL_IMM : CL_ADR;
case PUSHER:
return CL_ADR;
case REGVAR:
if (np->g_rno < AREG)
return CL_DREG;
else
return CL_AREG;
default:
printf("Weird class ");
return CL_IMM;
}
}
int canswap;
NODEP matchnp;
fix_cmp(np, flags)
NODEP np;
{
NODEP rp = np->n_right;
/* special stuff for ICON 0 */
if (rp->g_token == ICON && rp->g_offs == 0 &&
(rp->g_flags & IMMEDID)) {
addcode(np, "<Q");
return OKAY;
}
canswap = 0;
return fix_sub(np, flags, tblc);
}
fix2ops(np, flags)
NODEP np;
{
canswap = flags & ASSOC;
return fix_sub(np, flags, tbl2);
}
fixmul(np, flags)
NODEP np;
{
return fix_sub(np, flags, tblmul);
}
fixdiv(np, flags)
NODEP np;
{
return fix_sub(np, flags, np->g_ty == ET_U ? tbludiv : tbldiv);
}
fixmod(np, flags)
NODEP np;
{
int r;
r = fixdiv(np, flags);
addcode(np, "\tswap\tA\n");
return r;
}
fixamul(np, flags)
NODEP np;
{
return fix_sub(np, flags, tblamul);
}
fixadiv(np, flags)
NODEP np;
{
return fix_sub(np, flags, np->g_ty == ET_U ? tbluadiv : tbladiv);
}
fixamod(np, flags)
NODEP np;
{
return fix_sub(np, flags, np->g_ty == ET_U ? tbluamod : tblamod);
}
fix_asn(np, flags)
NODEP np;
{
canswap = 0;
return fix_sub(np, flags, tblas);
}
fix_sub(np, flags, tbl)
register NODEP np;
struct mtbl *tbl;
{
NODEP lp = np->n_left, rp = np->n_right;
int lclass, rclass;
register struct mtbl *p;
int rv;
lclass = class(lp);
rclass = class(rp);
matchnp = np;
for (p = tbl; p->restr; p++)
if ((rv = cando(flags, p->restr, lclass, rclass))) {
dotbl(p, np);
return OKAY;
}
printf("no code table match! ");
return FAIL;
}
dotbl(p, np)
struct mtbl *p;
NODEP np;
{
register int i, k;
if (p->needregs) {
i = p->needregs;
if (i & RETLEFT)
inherit(np);
else if (i & RETRIGHT)
rinherit(np);
else if (i & RETAREG)
retreg(np, ralloc(AREG));
else if (i & RETDREG)
retreg(np, ralloc(0));
k = i & 7;
while (k--)
tempr(np, 0);
k = (i/AREG) & 7;
while (k--)
tempr(np, AREG);
}
addcode(np, p->code);
}
#define canflag(l,r) (l << cansh[r])
short cansh[] = {0, 0, 4, 0, 8, 0, 0, 0, 12};
cando(flags, restr, lc, rc)
register restr;
{
NODEP lp = matchnp->n_left, rp = matchnp->n_right;
if (restr & RISTMP) {
if ((rc & (CL_DREG|CL_AREG)) == 0 ||
istemp(rp->g_rno) == 0)
return 0;
} else if (restr & LISTMP) {
if ((lc & (CL_DREG|CL_AREG)) == 0 ||
istemp(lp->g_rno) == 0)
return 0;
}
if (restr & NDASSOC) {
if (canswap == 0)
return 0;
}
if (restr & (CANLR|CANLD)) {
flags |= quickflag(lp, flags);
} else if (restr & (CANRL|CANRD)) {
flags |= quickflag(rp, flags);
}
flags &= 0xfff;
if (restr & CANLR) {
if ((flags & canflag(lc,rc)) == 0)
return 0;
} else if (restr & CANRL) {
if ((flags & canflag(rc,lc)) == 0)
return 0;
} else if (restr & CANRD) {
if ((flags & canflag(rc,CL_DREG)) == 0)
return 0;
} else if (restr & CANDL) {
if ((flags & canflag(CL_DREG,lc)) == 0)
return 0;
} else if (restr & CANLD) {
if ((flags & canflag(lc,CL_DREG)) == 0)
return 0;
} else if (restr & CANDR) {
if ((flags & canflag(CL_DREG,rc)) == 0)
return 0;
} else if (restr & CANDD) {
if ((flags & DOPD) == 0)
return 0;
}
return 1;
}
quickflag(np, flags)
NODEP np;
{
long offs;
if (np->g_token != ICON)
return 0;
offs = np->g_offs;
if ((flags & QOPD) && np->g_offs >= 1 && np->g_offs <= 8)
return IOPD;
if ((flags & ONEOPM) && np->g_offs == 1)
return IOPM;
return 0;
}
/*
* stuff to do field extract and field assign
* Yes, this stuff can be optimized a lot more ... feel free
*/
fldget(np, flags)
register NODEP np;
{
int how;
how = 1;
if (np->g_fldo == 0)
how = 0; /* no shift needed */
else if (np->g_fldo > 8)
how = 2; /* shift too big for immediate */
np->n_left->g_offs += np->g_offs; /* major HACK, hope it works */
retreg(np, ralloc(0));
addcode(np, "\tmove\t<A,A\n"); /* get word */
if (how) /* shift to position */
addcode(np, how==1 ? "\tlsr\t#Y,A\n" :
"\tlsr\t#8,A\n\tlsr\t#Z,A\n");
addcode(np, "\tand\t#W,A\n"); /* mask off top */
return OKAY;
}
fldasn(np, flags)
register NODEP np;
{
int how;
how = 1;
if (np->g_fldo == 0)
how = 0; /* no shift needed */
else if (np->g_fldo > 8)
how = 2; /* shift too big for immediate */
retreg(np, ralloc(0));
tempr(np, 0);
addcode(np, "\tmove\t>A,A\n"); /* value */
if (needmask(np)) /* mask off high bits */
addcode(np, "\tand\t#W,A\n");
if (how) /* shift into position */
addcode(np, how==1 ? "\tlsl\t#Y,A\n" :
"\tlsl\t#8,A\n\tlsl\t#Z,A\n");
addcode(np, "\tmove\t<A,R1\n"); /* old value */
addcode(np, "\tand\t#X,R1\n"); /* mask out old value */
addcode(np, "\tor\tA,R1\n"); /* set new field */
addcode(np, "\tmove\tR1,<A\n"); /* store new word */
if (how && (flags & NOVAL_OK) == 0) /* return value */
addcode(np, how==1 ? "\tlsr\t#Y,A\n" :
"\tlsr\t#8,A\n\tlsr\t#Z,A\n");
return OKAY;
}
needmask(np)
register NODEP np;
{
NODEP lp = np->n_left;
if (np->g_fldw + np->g_fldo >= 16)
return 0;
if (lp->g_token != ICON)
return 1;
if ((int)lp->g_offs & ~ones(np->g_fldw)) {
warn("value too big for field");
return 1;
}
return 0;
}